extends Node2D
class_name DungeonGenerator

# 地牢生成器 - 使用BSP（Binary Space Partitioning）算法
# 这是一个教程式的实现，帮助学习Godot 4地图开发

# ===== 导出参数 - 可在编辑器中调整 =====
@export_group("地牢尺寸")
@export var dungeon_width: int = 30  # 地牢总宽度（瓦片数）- 匹配480px viewport
@export var dungeon_height: int = 17  # 地牢总高度（瓦片数）- 匹配270px viewport

@export_group("房间设置")
@export var room_count: int = 6  # 目标房间数量（适应较小地图）
@export var room_min_size: Vector2i = Vector2i(4, 3)  # 房间最小尺寸（适应小地图）
@export var room_max_size: Vector2i = Vector2i(8, 6)  # 房间最大尺寸（适应小地图）
@export var room_padding: int = 1  # 房间之间的最小间距（减少以适应小地图）

@export_group("走廊设置")
@export var corridor_width: int = 1  # 走廊宽度
@export var corridor_windiness: float = 0.3  # 走廊弯曲程度 (0-1)

@export_group("生成设置")
@export var seed_value: int = 0  # 随机种子，0为随机
@export var max_split_depth: int = 3  # BSP最大分割深度（减少以适应小地图）

# ===== 瓦片类型枚举 =====
enum TileType {
	VOID = -1,           # 空白区域
	FLOOR = 0,           # 基础地板
	FLOOR_VARIANT1 = 1,  # 地板变种1
	FLOOR_VARIANT2 = 2,  # 地板变种2
	FLOOR_VARIANT3 = 3,  # 地板变种3
	WALL_TOP = 10,       # 顶部墙壁
	WALL_BOTTOM = 11,    # 底部墙壁
	WALL_LEFT = 12,      # 左侧墙壁
	WALL_RIGHT = 13,     # 右侧墙壁
	WALL_TOP_LEFT = 14,  # 左上角墙壁
	WALL_TOP_RIGHT = 15, # 右上角墙壁
	WALL_BOTTOM_LEFT = 16,  # 左下角墙壁
	WALL_BOTTOM_RIGHT = 17, # 右下角墙壁
	WALL_INNER_TOP_LEFT = 18,     # 内角左上
	WALL_INNER_TOP_RIGHT = 19,    # 内角右上
	WALL_INNER_BOTTOM_LEFT = 20,  # 内角左下
	WALL_INNER_BOTTOM_RIGHT = 21, # 内角右下
	WALL = 22,           # 通用墙壁（填充用）
	DOOR_CLOSED = 30,    # 关闭的门
	DOOR_OPEN = 31,      # 打开的门
	CORRIDOR = 40,       # 走廊
	STAIRS = 50          # 楼梯
}

# ===== 数据结构 =====
# BSP树节点
class BSPNode:
	var rect: Rect2i  # 节点区域
	var room: Rect2i  # 房间区域（如果是叶子节点）
	var left_child: BSPNode  # 左子节点
	var right_child: BSPNode  # 右子节点
	var is_leaf: bool = false  # 是否为叶子节点
	
	func _init(r: Rect2i):
		rect = r

# 房间数据
class Room:
	var rect: Rect2i  # 房间矩形
	var center: Vector2i  # 房间中心点
	var connected_rooms: Array[Room] = []  # 连接的房间
	
	func _init(r: Rect2i):
		rect = r
		center = Vector2i(r.position.x + r.size.x / 2, r.position.y + r.size.y / 2)

# ===== 内部变量 =====
var tilemap: TileMap  # 瓦片地图引用
var dungeon_grid: Array[Array]  # 地牢网格数据
var bsp_root: BSPNode  # BSP树根节点
var rooms: Array[Room] = []  # 所有房间
var spawn_points: Array[Vector2i] = []  # 生成点（玩家、敌人等）

# ===== 信号 =====
signal dungeon_generated(rooms: Array[Room], spawn_points: Array[Vector2i])

func _ready():
	print("🏗️ DungeonGenerator 初始化完成")
	# 自动根据viewport尺寸调整地牢大小
	auto_adjust_dungeon_size()

# ===== 自动调整地牢尺寸 =====
func auto_adjust_dungeon_size():
	# 获取项目设置中的viewport尺寸
	var viewport_width = ProjectSettings.get_setting("display/window/size/viewport_width", 480)
	var viewport_height = ProjectSettings.get_setting("display/window/size/viewport_height", 270)
	
	# 假设瓦片大小为16x16（从图集可以看出）
	var tile_size = 16
	
	# 计算合适的地牢尺寸（瓦片数量）
	var calculated_width = viewport_width / tile_size
	var calculated_height = viewport_height / tile_size
	
	# 更新地牢尺寸
	dungeon_width = calculated_width
	dungeon_height = calculated_height
	
	print("🔧 自动调整地牢尺寸:")
	print("   Viewport: ", viewport_width, "x", viewport_height, " 像素")
	print("   瓦片大小: ", tile_size, "x", tile_size, " 像素")
	print("   地牢尺寸: ", dungeon_width, "x", dungeon_height, " 瓦片")
	
	# 根据新的地牢尺寸调整房间参数
	adjust_room_parameters()

func adjust_room_parameters():
	# 根据地牢大小调整房间参数
	var dungeon_area = dungeon_width * dungeon_height
	
	# 较小的地牢需要较小的房间
	if dungeon_area < 600:  # 小地牢 (30x17 = 510)
		room_min_size = Vector2i(3, 3)
		room_max_size = Vector2i(7, 5)
		room_padding = 1
		max_split_depth = 3
		print("📐 小地牢配置: 房间 3-7x3-5, 间距 1, 深度 3")
	elif dungeon_area < 1500:  # 中等地牢
		room_min_size = Vector2i(4, 4)
		room_max_size = Vector2i(10, 8)
		room_padding = 2
		max_split_depth = 4
		print("📐 中等地牢配置: 房间 4-10x4-8, 间距 2, 深度 4")
	else:  # 大地牢
		room_min_size = Vector2i(6, 6)
		room_max_size = Vector2i(15, 12)
		room_padding = 3
		max_split_depth = 5
		print("📐 大地牢配置: 房间 6-15x6-12, 间距 3, 深度 5")

# ===== 主要生成函数 =====
func generate_dungeon(target_tilemap: TileMap = null) -> void:
	print("🎲 开始生成地牢...")
	
	# 设置随机种子
	if seed_value != 0:
		seed(seed_value)
		print("🌱 使用固定种子: ", seed_value)
	else:
		randomize()
		print("🌱 使用随机种子")
	
	# 获取TileMap引用
	if target_tilemap:
		tilemap = target_tilemap
		print("✅ 使用提供的TileMap: ", tilemap.name)
	else:
		# 尝试多种方式查找TileMap
		tilemap = get_parent().get_node_or_null("TileMap")
		if not tilemap:
			print("🔍 在父节点中未找到TileMap，尝试在场景树中查找...")
			var game_node = get_tree().get_first_node_in_group("game")
			if game_node:
				tilemap = game_node.get_node_or_null("TileMap")
			if not tilemap:
				# 最后尝试在当前节点的兄弟节点中查找
				var parent = get_parent()
				if parent:
					for child in parent.get_children():
						if child is TileMap:
							tilemap = child
							break
		
		if tilemap:
			print("✅ 找到TileMap: ", tilemap.name)
		else:
			print("❌ 错误：未找到TileMap节点！")
			print("🔍 可用的兄弟节点:")
			if get_parent():
				for child in get_parent().get_children():
					print("  - ", child.name, " (", child.get_class(), ")")
			return
	
	# 清理之前的数据
	clear_dungeon()
	
	# 第一步：初始化网格
	initialize_grid()
	
	# 第二步：BSP分割
	create_bsp_tree()
	
	# 第三步：创建房间
	create_rooms()
	
	# 第四步：连接房间（创建走廊）
	connect_rooms()
	
	# 第五步：生成墙壁
	generate_walls()
	
	# 第六步：放置门
	place_doors()
	
	# 第七步：添加特殊元素
	add_special_elements()
	
	# 第八步：确定生成点
	determine_spawn_points()
	
	# 第九步：应用到TileMap
	apply_to_tilemap()
	
	print("✅ 地牢生成完成！房间数量: ", rooms.size())
	print("📍 生成点数量: ", spawn_points.size())
	
	# 发出完成信号
	dungeon_generated.emit(rooms, spawn_points)

# ===== 第一步：初始化网格 =====
func initialize_grid():
	print("📋 初始化地牢网格...")
	
	dungeon_grid = []
	for x in range(dungeon_width):
		var column = []
		for y in range(dungeon_height):
			column.append(TileType.VOID)
		dungeon_grid.append(column)
	
	print("✅ 网格初始化完成: ", dungeon_width, "x", dungeon_height)

# ===== 第二步：BSP分割 =====
func create_bsp_tree():
	print("🌳 创建BSP树...")
	
	# 创建根节点
	var root_rect = Rect2i(1, 1, dungeon_width - 2, dungeon_height - 2)
	bsp_root = BSPNode.new(root_rect)
	
	# 递归分割
	split_node(bsp_root, 0)
	
	print("✅ BSP树创建完成")

func split_node(node: BSPNode, depth: int):
	# 检查是否应该停止分割
	if depth >= max_split_depth or should_stop_splitting(node.rect):
		node.is_leaf = true
		return
	
	# 决定分割方向（水平或垂直）
	var split_horizontal = decide_split_direction(node.rect)
	
	# 执行分割
	var split_pos = calculate_split_position(node.rect, split_horizontal)
	
	if split_pos == -1:
		# 无法分割，设为叶子节点
		node.is_leaf = true
		return
	
	# 创建子节点
	if split_horizontal:
		# 水平分割
		var top_rect = Rect2i(node.rect.position.x, node.rect.position.y, 
							 node.rect.size.x, split_pos - node.rect.position.y)
		var bottom_rect = Rect2i(node.rect.position.x, split_pos, 
								node.rect.size.x, node.rect.position.y + node.rect.size.y - split_pos)
		
		node.left_child = BSPNode.new(top_rect)
		node.right_child = BSPNode.new(bottom_rect)
	else:
		# 垂直分割
		var left_rect = Rect2i(node.rect.position.x, node.rect.position.y, 
							  split_pos - node.rect.position.x, node.rect.size.y)
		var right_rect = Rect2i(split_pos, node.rect.position.y, 
							   node.rect.position.x + node.rect.size.x - split_pos, node.rect.size.y)
		
		node.left_child = BSPNode.new(left_rect)
		node.right_child = BSPNode.new(right_rect)
	
	# 递归分割子节点
	split_node(node.left_child, depth + 1)
	split_node(node.right_child, depth + 1)

func should_stop_splitting(rect: Rect2i) -> bool:
	# 如果区域太小，停止分割
	var min_area = (room_max_size.x + room_padding * 2) * (room_max_size.y + room_padding * 2)
	return rect.size.x * rect.size.y < min_area * 2

func decide_split_direction(rect: Rect2i) -> bool:
	# 根据长宽比决定分割方向
	var aspect_ratio = float(rect.size.x) / float(rect.size.y)
	
	if aspect_ratio > 1.25:
		return false  # 垂直分割（太宽）
	elif aspect_ratio < 0.75:
		return true   # 水平分割（太高）
	else:
		return randi() % 2 == 0  # 随机选择

func calculate_split_position(rect: Rect2i, horizontal: bool) -> int:
	var min_size = room_max_size.x + room_padding * 2 if not horizontal else room_max_size.y + room_padding * 2
	var available_size = rect.size.x if not horizontal else rect.size.y
	var start_pos = rect.position.x if not horizontal else rect.position.y
	
	if available_size < min_size * 2:
		return -1  # 无法分割
	
	# 在有效范围内随机选择分割位置
	var min_split = start_pos + min_size
	var max_split = start_pos + available_size - min_size
	
	return randi_range(min_split, max_split)

# ===== 第三步：创建房间 =====
func create_rooms():
	print("🏠 创建房间...")
	
	rooms.clear()
	create_rooms_recursive(bsp_root)
	
	print("✅ 创建了 ", rooms.size(), " 个房间")

func create_rooms_recursive(node: BSPNode):
	if node.is_leaf:
		# 在叶子节点创建房间
		var room_rect = generate_room_in_area(node.rect)
		if room_rect.size.x > 0 and room_rect.size.y > 0:
			node.room = room_rect
			var room = Room.new(room_rect)
			rooms.append(room)
			
			# 在网格中标记房间，使用多样化的地板
			mark_room_with_varied_floor(room_rect)
	else:
		# 递归处理子节点
		if node.left_child:
			create_rooms_recursive(node.left_child)
		if node.right_child:
			create_rooms_recursive(node.right_child)

func generate_room_in_area(area: Rect2i) -> Rect2i:
	# 在给定区域内生成一个随机大小的房间
	var max_width = min(room_max_size.x, area.size.x - room_padding * 2)
	var max_height = min(room_max_size.y, area.size.y - room_padding * 2)
	
	if max_width < room_min_size.x or max_height < room_min_size.y:
		return Rect2i()  # 空房间
	
	var width = randi_range(room_min_size.x, max_width)
	var height = randi_range(room_min_size.y, max_height)
	
	var max_x = area.position.x + area.size.x - width - room_padding
	var max_y = area.position.y + area.size.y - height - room_padding
	
	var x = randi_range(area.position.x + room_padding, max_x)
	var y = randi_range(area.position.y + room_padding, max_y)
	
	return Rect2i(x, y, width, height)

# ===== 第四步：连接房间 =====
func connect_rooms():
	print("🔗 连接房间...")
	
	connect_rooms_recursive(bsp_root)
	
	print("✅ 房间连接完成")

func connect_rooms_recursive(node: BSPNode):
	if node.is_leaf:
		return  # 叶子节点不需要连接
	
	# 递归处理子节点
	if node.left_child:
		connect_rooms_recursive(node.left_child)
	if node.right_child:
		connect_rooms_recursive(node.right_child)
	
	# 连接左右子树的房间
	if node.left_child and node.right_child:
		var left_room = get_random_room_from_subtree(node.left_child)
		var right_room = get_random_room_from_subtree(node.right_child)
		
		if left_room and right_room:
			create_corridor(left_room.center, right_room.center)
			
			# 标记房间为已连接
			left_room.connected_rooms.append(right_room)
			right_room.connected_rooms.append(left_room)

func get_random_room_from_subtree(node: BSPNode) -> Room:
	if node.is_leaf and node.room.size.x > 0:
		# 找到对应的Room对象
		for room in rooms:
			if room.rect == node.room:
				return room
	
	# 随机选择一个子树
	var candidates: Array[Room] = []
	if node.left_child:
		var left_room = get_random_room_from_subtree(node.left_child)
		if left_room:
			candidates.append(left_room)
	
	if node.right_child:
		var right_room = get_random_room_from_subtree(node.right_child)
		if right_room:
			candidates.append(right_room)
	
	if candidates.size() > 0:
		return candidates[randi() % candidates.size()]
	
	return null

func create_corridor(start: Vector2i, end: Vector2i):
	# 创建L形走廊连接两个点
	var current = start
	var target = end
	
	# 决定先走哪个方向
	var horizontal_first = randf() < 0.5
	
	if horizontal_first:
		# 先水平移动
		create_horizontal_corridor(current, target.x)
		current.x = target.x
		# 再垂直移动
		create_vertical_corridor(current, target.y)
	else:
		# 先垂直移动
		create_vertical_corridor(current, target.y)
		current.y = target.y
		# 再水平移动
		create_horizontal_corridor(current, target.x)

func create_horizontal_corridor(start: Vector2i, target_x: int):
	var y = start.y
	var from_x = min(start.x, target_x)
	var to_x = max(start.x, target_x)
	
	for x in range(from_x, to_x + 1):
		if is_valid_position(x, y):
			if dungeon_grid[x][y] == TileType.VOID:
				dungeon_grid[x][y] = TileType.CORRIDOR

func create_vertical_corridor(start: Vector2i, target_y: int):
	var x = start.x
	var from_y = min(start.y, target_y)
	var to_y = max(start.y, target_y)
	
	for y in range(from_y, to_y + 1):
		if is_valid_position(x, y):
			if dungeon_grid[x][y] == TileType.VOID:
				dungeon_grid[x][y] = TileType.CORRIDOR

# ===== 第五步：生成墙壁 =====
func generate_walls():
	print("🧱 生成智能墙壁...")
	
	# 第一步：标记所有需要墙壁的位置
	for x in range(dungeon_width):
		for y in range(dungeon_height):
			if dungeon_grid[x][y] == TileType.VOID:
				if should_be_wall(x, y):
					dungeon_grid[x][y] = TileType.WALL  # 临时标记
	
	# 第二步：根据周围环境选择正确的墙壁类型
	for x in range(dungeon_width):
		for y in range(dungeon_height):
			if dungeon_grid[x][y] == TileType.WALL:
				dungeon_grid[x][y] = get_smart_wall_type(x, y)
	
	print("✅ 智能墙壁生成完成")

func should_be_wall(x: int, y: int) -> bool:
	# 如果相邻有地板或走廊，则应该是墙壁
	for dx in range(-1, 2):
		for dy in range(-1, 2):
			var nx = x + dx
			var ny = y + dy
			
			if is_valid_position(nx, ny):
				var tile_type = dungeon_grid[nx][ny]
				if is_floor_type(tile_type) or tile_type == TileType.CORRIDOR:
					return true
	
	return false

func is_floor_type(tile_type: TileType) -> bool:
	return tile_type == TileType.FLOOR or tile_type == TileType.FLOOR_VARIANT1 or tile_type == TileType.FLOOR_VARIANT2 or tile_type == TileType.FLOOR_VARIANT3

func get_smart_wall_type(x: int, y: int) -> TileType:
	# 检查八个方向的邻居
	var has_floor_up = is_valid_position(x, y-1) and is_floor_or_corridor(x, y-1)
	var has_floor_down = is_valid_position(x, y+1) and is_floor_or_corridor(x, y+1)
	var has_floor_left = is_valid_position(x-1, y) and is_floor_or_corridor(x-1, y)
	var has_floor_right = is_valid_position(x+1, y) and is_floor_or_corridor(x+1, y)
	var has_floor_up_left = is_valid_position(x-1, y-1) and is_floor_or_corridor(x-1, y-1)
	var has_floor_up_right = is_valid_position(x+1, y-1) and is_floor_or_corridor(x+1, y-1)
	var has_floor_down_left = is_valid_position(x-1, y+1) and is_floor_or_corridor(x-1, y+1)
	var has_floor_down_right = is_valid_position(x+1, y+1) and is_floor_or_corridor(x+1, y+1)
	
	# 根据相邻的地板位置决定墙壁类型
	
	# 外角检测
	if has_floor_down and has_floor_right and not has_floor_down_right:
		return TileType.WALL_BOTTOM_RIGHT
	if has_floor_down and has_floor_left and not has_floor_down_left:
		return TileType.WALL_BOTTOM_LEFT
	if has_floor_up and has_floor_right and not has_floor_up_right:
		return TileType.WALL_TOP_RIGHT
	if has_floor_up and has_floor_left and not has_floor_up_left:
		return TileType.WALL_TOP_LEFT
	
	# 内角检测
	if not has_floor_up and not has_floor_left and has_floor_up_left:
		return TileType.WALL_INNER_TOP_LEFT
	if not has_floor_up and not has_floor_right and has_floor_up_right:
		return TileType.WALL_INNER_TOP_RIGHT
	if not has_floor_down and not has_floor_left and has_floor_down_left:
		return TileType.WALL_INNER_BOTTOM_LEFT
	if not has_floor_down and not has_floor_right and has_floor_down_right:
		return TileType.WALL_INNER_BOTTOM_RIGHT
	
	# 直边检测
	if has_floor_down and not has_floor_up:
		return TileType.WALL_TOP
	if has_floor_up and not has_floor_down:
		return TileType.WALL_BOTTOM
	if has_floor_right and not has_floor_left:
		return TileType.WALL_LEFT
	if has_floor_left and not has_floor_right:
		return TileType.WALL_RIGHT
	
	# 默认墙壁
	return TileType.WALL

func is_floor_or_corridor(x: int, y: int) -> bool:
	if not is_valid_position(x, y):
		return false
	var tile_type = dungeon_grid[x][y]
	return is_floor_type(tile_type) or tile_type == TileType.CORRIDOR

# ===== 第六步：放置门 =====
func place_doors():
	print("🚪 放置门...")
	
	var door_count = 0
	
	# 在走廊与房间的连接点放置门
	for room in rooms:
		var door_positions = find_door_positions(room)
		for pos in door_positions:
			if is_valid_position(pos.x, pos.y):
				dungeon_grid[pos.x][pos.y] = TileType.DOOR_CLOSED
				door_count += 1
	
	print("✅ 放置了 ", door_count, " 扇门")

func find_door_positions(room: Room) -> Array[Vector2i]:
	var doors: Array[Vector2i] = []
	var rect = room.rect
	
	# 检查房间边缘，寻找与走廊相邻的位置
	# 上边缘
	for x in range(rect.position.x, rect.position.x + rect.size.x):
		var y = rect.position.y - 1
		if is_valid_position(x, y) and dungeon_grid[x][y] == TileType.CORRIDOR:
			doors.append(Vector2i(x, rect.position.y))
	
	# 下边缘
	for x in range(rect.position.x, rect.position.x + rect.size.x):
		var y = rect.position.y + rect.size.y
		if is_valid_position(x, y) and dungeon_grid[x][y] == TileType.CORRIDOR:
			doors.append(Vector2i(x, rect.position.y + rect.size.y - 1))
	
	# 左边缘
	for y in range(rect.position.y, rect.position.y + rect.size.y):
		var x = rect.position.x - 1
		if is_valid_position(x, y) and dungeon_grid[x][y] == TileType.CORRIDOR:
			doors.append(Vector2i(rect.position.x, y))
	
	# 右边缘
	for y in range(rect.position.y, rect.position.y + rect.size.y):
		var x = rect.position.x + rect.size.x
		if is_valid_position(x, y) and dungeon_grid[x][y] == TileType.CORRIDOR:
			doors.append(Vector2i(rect.position.x + rect.size.x - 1, y))
	
	return doors

# ===== 第七步：添加特殊元素 =====
func add_special_elements():
	print("✨ 添加特殊元素...")
	
	var elements_added = 0
	
	# 在最后一个房间添加楼梯（作为出口）
	if rooms.size() > 0:
		var last_room = rooms[rooms.size() - 1]
		var stair_pos = Vector2i(
			last_room.center.x + randi_range(-1, 1),
			last_room.center.y + randi_range(-1, 1)
		)
		
		# 确保楼梯位置在房间内
		stair_pos.x = clamp(stair_pos.x, last_room.rect.position.x + 1, 
							last_room.rect.position.x + last_room.rect.size.x - 2)
		stair_pos.y = clamp(stair_pos.y, last_room.rect.position.y + 1, 
							last_room.rect.position.y + last_room.rect.size.y - 2)
		
		if is_valid_position(stair_pos.x, stair_pos.y):
			dungeon_grid[stair_pos.x][stair_pos.y] = TileType.STAIRS
			elements_added += 1
			print("🪜 在房间 ", rooms.size(), " 添加了楼梯")
	
	# 随机在一些房间添加地板变种（增加视觉趣味）
	for i in range(rooms.size()):
		var room = rooms[i]
		# 30%概率为房间添加特殊地板图案
		if randf() < 0.3:
			add_floor_pattern_to_room(room)
			elements_added += 1
	
	print("✅ 添加了 ", elements_added, " 个特殊元素")

func add_floor_pattern_to_room(room: Room):
	# 在房间中添加一些装饰性的地板图案
	var pattern_type = randi() % 3
	
	match pattern_type:
		0:
			# 中心十字图案
			var center = room.center
			if is_valid_position(center.x, center.y):
				dungeon_grid[center.x][center.y] = TileType.FLOOR_VARIANT2
			if is_valid_position(center.x - 1, center.y):
				dungeon_grid[center.x - 1][center.y] = TileType.FLOOR_VARIANT1
			if is_valid_position(center.x + 1, center.y):
				dungeon_grid[center.x + 1][center.y] = TileType.FLOOR_VARIANT1
			if is_valid_position(center.x, center.y - 1):
				dungeon_grid[center.x][center.y - 1] = TileType.FLOOR_VARIANT1
			if is_valid_position(center.x, center.y + 1):
				dungeon_grid[center.x][center.y + 1] = TileType.FLOOR_VARIANT1
		
		1:
			# 角落装饰
			var corners = [
				Vector2i(room.rect.position.x + 1, room.rect.position.y + 1),
				Vector2i(room.rect.position.x + room.rect.size.x - 2, room.rect.position.y + 1),
				Vector2i(room.rect.position.x + 1, room.rect.position.y + room.rect.size.y - 2),
				Vector2i(room.rect.position.x + room.rect.size.x - 2, room.rect.position.y + room.rect.size.y - 2)
			]
			
			for corner in corners:
				if is_valid_position(corner.x, corner.y) and randf() < 0.5:
					dungeon_grid[corner.x][corner.y] = TileType.FLOOR_VARIANT3
		
		2:
			# 随机散点
			for attempt in range(5):
				var rand_x = randi_range(room.rect.position.x + 1, room.rect.position.x + room.rect.size.x - 2)
				var rand_y = randi_range(room.rect.position.y + 1, room.rect.position.y + room.rect.size.y - 2)
				
				if is_valid_position(rand_x, rand_y):
					dungeon_grid[rand_x][rand_y] = TileType.FLOOR_VARIANT1

# ===== 第八步：确定生成点 =====
func determine_spawn_points():
	print("📍 确定生成点...")
	
	spawn_points.clear()
	
	# 为每个房间添加一个生成点（房间中心附近）
	for room_index in range(rooms.size()):
		var room = rooms[room_index]
		print("🏠 处理房间 ", room_index + 1, ": ", room.rect, " 中心: ", room.center)
		
		var spawn_pos = Vector2i.ZERO
		var found_valid_spawn = false
		var attempts = 0
		var max_attempts = 20
		
		# 尝试多次找到房间内的有效地板位置
		while not found_valid_spawn and attempts < max_attempts:
			attempts += 1
			
			# 在房间中心附近随机选择位置
			spawn_pos = Vector2i(
				room.center.x + randi_range(-3, 3),
				room.center.y + randi_range(-3, 3)
			)
			
			# 确保生成点在房间内
			spawn_pos.x = clamp(spawn_pos.x, room.rect.position.x + 1, 
								room.rect.position.x + room.rect.size.x - 2)
			spawn_pos.y = clamp(spawn_pos.y, room.rect.position.y + 1, 
								room.rect.position.y + room.rect.size.y - 2)
			
			# 检查这个位置是否是地板
			if is_valid_position(spawn_pos.x, spawn_pos.y):
				var tile_type = dungeon_grid[spawn_pos.x][spawn_pos.y]
				if tile_type in [TileType.FLOOR, TileType.FLOOR_VARIANT1, TileType.FLOOR_VARIANT2, TileType.FLOOR_VARIANT3]:
					found_valid_spawn = true
					print("✅ 房间 ", room_index + 1, " 找到有效生成点: ", spawn_pos, " (尝试 ", attempts, " 次)")
				else:
					print("❌ 房间 ", room_index + 1, " 位置 ", spawn_pos, " 不是地板，瓦片类型: ", tile_type)
		
		if found_valid_spawn:
			spawn_points.append(spawn_pos)
		else:
			# 如果找不到有效位置，使用房间中心作为备用
			print("⚠️ 房间 ", room_index + 1, " 无法找到有效地板，使用房间中心: ", room.center)
			spawn_points.append(room.center)
	
	print("✅ 确定了 ", spawn_points.size(), " 个生成点")
	
	# 打印所有生成点的详细信息
	print("📍 生成点详细信息:")
	for i in range(spawn_points.size()):
		var spawn_point = spawn_points[i]
		var tile_type = dungeon_grid[spawn_point.x][spawn_point.y] if is_valid_position(spawn_point.x, spawn_point.y) else "INVALID"
		print("  ", i, ": 瓦片坐标=", spawn_point, " 瓦片类型=", tile_type)

# ===== 第八步：应用到TileMap =====
func apply_to_tilemap():
	print("🗺️ 应用到TileMap...")
	
	if not tilemap:
		print("❌ 错误：TileMap未设置！")
		return
	
	# 清空现有瓦片
	tilemap.clear()
	print("✅ TileMap已清空")
	
	# 确保TileMap有物理层用于碰撞
	setup_tilemap_physics()
	
	# 统计要放置的瓦片数量
	var tile_counts = {"floor": 0, "wall": 0, "door": 0, "corridor": 0, "stairs": 0}
	
	# 应用瓦片
	for x in range(dungeon_width):
		for y in range(dungeon_height):
			var tile_type = dungeon_grid[x][y]
			var source_id = 0  # 使用正确的source ID（TileSet中是sources/0）
			var atlas_coords = get_atlas_coords_for_tile_type(tile_type)
			
			if atlas_coords != Vector2i(-1, -1):
				tilemap.set_cell(0, Vector2i(x, y), source_id, atlas_coords)
				
				# 为墙壁瓦片设置碰撞
				if is_wall_tile_type(tile_type):
					setup_wall_collision(Vector2i(x, y), tile_type)
				
				# 统计瓦片类型
				match tile_type:
					TileType.FLOOR, TileType.FLOOR_VARIANT1, TileType.FLOOR_VARIANT2, TileType.FLOOR_VARIANT3:
						tile_counts["floor"] += 1
					TileType.WALL_TOP, TileType.WALL_BOTTOM, TileType.WALL_LEFT, TileType.WALL_RIGHT, TileType.WALL_TOP_LEFT, TileType.WALL_TOP_RIGHT, TileType.WALL_BOTTOM_LEFT, TileType.WALL_BOTTOM_RIGHT, TileType.WALL_INNER_TOP_LEFT, TileType.WALL_INNER_TOP_RIGHT, TileType.WALL_INNER_BOTTOM_LEFT, TileType.WALL_INNER_BOTTOM_RIGHT, TileType.WALL:
						tile_counts["wall"] += 1
					TileType.DOOR_CLOSED, TileType.DOOR_OPEN:
						tile_counts["door"] += 1
					TileType.CORRIDOR:
						tile_counts["corridor"] += 1
					TileType.STAIRS:
						tile_counts["stairs"] += 1
	
	print("✅ TileMap应用完成")
	print("📊 瓦片统计: 地板=", tile_counts["floor"], " 墙壁=", tile_counts["wall"], " 门=", tile_counts["door"], " 走廊=", tile_counts["corridor"], " 楼梯=", tile_counts["stairs"])
	print("🧱 墙壁碰撞系统已启用")

# ===== 物理碰撞系统 =====
func setup_tilemap_physics():
	# 确保TileSet有物理层
	if not tilemap.tile_set:
		print("❌ TileMap没有TileSet!")
		return
	
	# 检查是否已有物理层，如果没有则添加
	var physics_layers_count = tilemap.tile_set.get_physics_layers_count()
	if physics_layers_count == 0:
		tilemap.tile_set.add_physics_layer()
		print("✅ 添加了物理层到TileSet")
	
	# 设置物理层属性
	tilemap.tile_set.set_physics_layer_collision_layer(0, 2)  # 墙壁层
	tilemap.tile_set.set_physics_layer_collision_mask(0, 0)   # 墙壁不检测其他物体
	
	# 为墙壁瓦片添加碰撞形状
	setup_wall_collision_shapes()

func setup_wall_collision_shapes():
	if not tilemap.tile_set or tilemap.tile_set.get_source_count() == 0:
		return
	
	var source = tilemap.tile_set.get_source(0)
	if not source is TileSetAtlasSource:
		return
	
	var atlas_source = source as TileSetAtlasSource
	
	# 为所有墙壁瓦片添加碰撞形状
	var wall_coords = [
		Vector2i(1, 0),   # wall_top
		Vector2i(1, 2),   # wall_bottom
		Vector2i(0, 1),   # wall_left
		Vector2i(2, 1),   # wall_right
		Vector2i(0, 0),   # wall_top_left
		Vector2i(2, 0),   # wall_top_right
		Vector2i(0, 2),   # wall_bottom_left
		Vector2i(2, 2),   # wall_bottom_right
		Vector2i(0, 3),   # wall_inner_top_left
		Vector2i(2, 3),   # wall_inner_top_right
		Vector2i(6, 4),   # wall_inner_bottom_left
		Vector2i(8, 4),   # wall_inner_bottom_right
		Vector2i(1, 1),   # 通用墙壁
	]
	
	for coords in wall_coords:
		if atlas_source.has_tile(coords):
			var tile_data = atlas_source.get_tile_data(coords, 0)
			if tile_data:
				# 创建矩形碰撞形状（覆盖整个瓦片）
				var collision_shape = RectangleShape2D.new()
				collision_shape.size = Vector2(16, 16)  # 瓦片大小
				
				# 添加碰撞多边形
				var collision_polygon = PackedVector2Array([
					Vector2(-8, -8),   # 左上
					Vector2(8, -8),    # 右上
					Vector2(8, 8),     # 右下
					Vector2(-8, 8)     # 左下
				])
				
				tile_data.add_collision_polygon(0)
				tile_data.set_collision_polygon_points(0, 0, collision_polygon)
				
				print("🧱 为墙壁瓦片 ", coords, " 添加了碰撞形状")

func is_wall_tile_type(tile_type: TileType) -> bool:
	return tile_type in [
		TileType.WALL_TOP,
		TileType.WALL_BOTTOM,
		TileType.WALL_LEFT,
		TileType.WALL_RIGHT,
		TileType.WALL_TOP_LEFT,
		TileType.WALL_TOP_RIGHT,
		TileType.WALL_BOTTOM_LEFT,
		TileType.WALL_BOTTOM_RIGHT,
		TileType.WALL_INNER_TOP_LEFT,
		TileType.WALL_INNER_TOP_RIGHT,
		TileType.WALL_INNER_BOTTOM_LEFT,
		TileType.WALL_INNER_BOTTOM_RIGHT,
		TileType.WALL
	]

func setup_wall_collision(tile_pos: Vector2i, tile_type: TileType):
	# 这个函数现在主要用于调试，实际碰撞由TileSet处理
	pass

func get_atlas_coords_for_tile_type(tile_type: TileType) -> Vector2i:
	# 根据瓦片类型返回对应的图集坐标
	match tile_type:
		# 地板瓦片
		TileType.FLOOR:
			return Vector2i(3, 4)  # floor_1
		TileType.FLOOR_VARIANT1:
			return Vector2i(4, 4)  # floor_2
		TileType.FLOOR_VARIANT2:
			return Vector2i(3, 5)  # floor_3
		TileType.FLOOR_VARIANT3:
			return Vector2i(4, 5)  # floor_4
		
		# 墙壁瓦片
		TileType.WALL_TOP:
			return Vector2i(1, 0)  # wall_top
		TileType.WALL_BOTTOM:
			return Vector2i(1, 2)  # wall_bottom
		TileType.WALL_LEFT:
			return Vector2i(0, 1)  # wall_left
		TileType.WALL_RIGHT:
			return Vector2i(2, 1)  # wall_right
		TileType.WALL_TOP_LEFT:
			return Vector2i(0, 0)  # wall_top_left
		TileType.WALL_TOP_RIGHT:
			return Vector2i(2, 0)  # wall_top_right
		TileType.WALL_BOTTOM_LEFT:
			return Vector2i(0, 2)  # wall_bottom_left
		TileType.WALL_BOTTOM_RIGHT:
			return Vector2i(2, 2)  # wall_bottom_right
		TileType.WALL_INNER_TOP_LEFT:
			return Vector2i(0, 3)  # wall_inner_top_left
		TileType.WALL_INNER_TOP_RIGHT:
			return Vector2i(2, 3)  # wall_inner_top_right
		TileType.WALL_INNER_BOTTOM_LEFT:
			return Vector2i(6, 4)  # wall_inner_bottom_left
		TileType.WALL_INNER_BOTTOM_RIGHT:
			return Vector2i(8, 4)  # wall_inner_bottom_right
		TileType.WALL:
			return Vector2i(1, 1)  # 通用墙壁填充
		
		# 门瓦片
		TileType.DOOR_CLOSED:
			return Vector2i(1, 6)  # door_closed
		TileType.DOOR_OPEN:
			return Vector2i(2, 6)  # door_open
		
		# 走廊瓦片
		TileType.CORRIDOR:
			return Vector2i(3, 4)  # 使用基础地板
		
		# 楼梯瓦片
		TileType.STAIRS:
			return Vector2i(7, 4)  # stairs
		
		_:
			return Vector2i(-1, -1)  # 不放置瓦片

# ===== 工具函数 =====
func is_valid_position(x: int, y: int) -> bool:
	return x >= 0 and x < dungeon_width and y >= 0 and y < dungeon_height

func mark_area(rect: Rect2i, tile_type: TileType):
	for x in range(rect.position.x, rect.position.x + rect.size.x):
		for y in range(rect.position.y, rect.position.y + rect.size.y):
			if is_valid_position(x, y):
				dungeon_grid[x][y] = tile_type

func mark_room_with_varied_floor(rect: Rect2i):
	# 为房间创建多样化的地板
	for x in range(rect.position.x, rect.position.x + rect.size.x):
		for y in range(rect.position.y, rect.position.y + rect.size.y):
			if is_valid_position(x, y):
				# 90%基础地板，10%变种地板
				var rand_val = randf()
				if rand_val < 0.9:
					dungeon_grid[x][y] = TileType.FLOOR
				elif rand_val < 0.95:
					dungeon_grid[x][y] = TileType.FLOOR_VARIANT1
				elif rand_val < 0.98:
					dungeon_grid[x][y] = TileType.FLOOR_VARIANT2
				else:
					dungeon_grid[x][y] = TileType.FLOOR_VARIANT3

func clear_dungeon():
	rooms.clear()
	spawn_points.clear()
	bsp_root = null
	dungeon_grid.clear()

# ===== 公共接口函数 =====
func get_room_at_position(world_pos: Vector2) -> Room:
	# 获取世界坐标对应的房间
	var tile_pos = tilemap.local_to_map(world_pos)
	
	for room in rooms:
		if room.rect.has_point(tile_pos):
			return room
	
	return null

func get_random_spawn_point() -> Vector2:
	# 获取随机生成点的世界坐标
	if spawn_points.size() == 0:
		return Vector2.ZERO
	
	var spawn_tile = spawn_points[randi() % spawn_points.size()]
	return tilemap.map_to_local(spawn_tile)

func get_player_spawn_point() -> Vector2:
	# 获取玩家生成点（通常是第一个房间）
	if spawn_points.size() == 0:
		print("⚠️ 没有可用的生成点，返回零坐标")
		return Vector2.ZERO
	
	var spawn_tile = spawn_points[0]  # 第一个生成点作为玩家生成点
	var world_pos = tilemap.map_to_local(spawn_tile)
	print("🎯 玩家生成点: 瓦片坐标=", spawn_tile, " 世界坐标=", world_pos)
	return world_pos

# ===== 调试函数 =====
func print_dungeon_stats():
	print("=== 地牢统计信息 ===")
	print("地牢尺寸: ", dungeon_width, "x", dungeon_height)
	print("房间数量: ", rooms.size())
	print("生成点数量: ", spawn_points.size())
	
	for i in range(rooms.size()):
		var room = rooms[i]
		print("房间 ", i + 1, ": ", room.rect, " 中心: ", room.center) 
